<?php

use Illuminate\Http\File;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Facades\Image;

/**
 * JSON encode data which is array or object.
 *
 * @param mixed $value Data that might be JSON encoded.
 * @return mixed A scalar data.
 */
function maybe_json_encode($value)
{
    if (is_array($value) || is_object($value)) {
        $value = json_encode($value);
    }

    return $value;
}

/**
 * JSON decode value only if it was JSON encoded.
 *
 * @param string $value Maybe JSON encoded value, if is needed.
 * @param bool $assoc
 * @return mixed
 */
function maybe_json_decode($value, $assoc = false)
{
    if (! is_string($value)) {
        return $value;
    }

    $decoded = json_decode($value, $assoc);
    if (json_last_error() == JSON_ERROR_NONE && (is_array($decoded) || is_object($decoded))) {
        return $decoded;
    } else {
        // Reset the JSON error code:
        json_decode('[]');

        return $value;
    }
}

function checked($checked, $current = true)
{
    return html_checked_selected($checked, $current, 'checked');
}

function selected($selected, $current = true)
{
    return html_checked_selected($selected, $current, 'selected');
}

function disabled($disabled, $current = true)
{
    return html_checked_selected($disabled, $current, 'disabled');
}

function html_checked_selected($compare, $current, $type)
{
    return (string) $compare === (string) $current ? " $type='$type'" : '';
}

function str_explode_trim($value)
{
    return array_map('trim', explode("\n", $value));
}

function is_phone($phone)
{
    return $phone ? preg_match('/^1[34578]\d{9}$/', $phone) : false;
}

/**
 * 生成随机数字串
 *
 * @param int $length 随机数字串长度
 * @return string
 */
function number_random($length = 16)
{
    $string = '';

    while (($len = strlen($string)) < $length) {
        $size = $length - $len;

        $number = strval(mt_rand(1000000000, 9999999999));

        $string .= substr($number, 0, $size);
    }

    return $string;
}

/**
 * 给链接添加查询参数
 *
 * @param array $args
 * @param string $uri
 * @return string
 */
function add_query_arg($args, $uri = '')
{
    if (empty($uri)) {
        $uri = $_SERVER['REQUEST_URI'];
    }

    $frag = strval(strstr($uri, '#'));
    if ($frag) {
        $uri = substr($uri, 0, -strlen($frag));
    }

    parse_str(parse_url($uri, PHP_URL_QUERY), $qs);
    foreach ($args as $k => $v) {
        $qs[$k] = $v;
    }

    foreach ($qs as $k => $v) {
        if ($v === false) {
            unset($qs[$k]);
        }
    }

    if (! $base = strstr($uri, '?', true)) {
        $base = $uri;
    }

    $query = http_build_query($qs);
    if ($query) {
        $base .= '?';
    }

    return $base . $query . $frag;
}

/**
 * 替换路径分隔符
 *
 * @param string $path
 * @param string $type dir or url
 * @return mixed
 */
function replace_path_separator($path, $type = 'dir')
{
    if ('url' == $type) {
        return str_replace('\\', '/', $path);
    }

    return str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
}

/**
 * 去掉path中的 '/./', '/../' 以及多余的 '/'
 *
 * @param string $path
 * @return string
 */
function get_absolute_path($path)
{
    $path = replace_path_separator($path);
    $first_slash = substr($path, 0, 1) == DIRECTORY_SEPARATOR ? DIRECTORY_SEPARATOR : '';

    $absolutes = [];
    $parts = explode(DIRECTORY_SEPARATOR, $path);
    foreach ($parts as $part) {
        if ('' === $part || '.' == $part) {
            continue;
        }

        if ('..' == $part) {
            array_pop($absolutes);
        } else {
            $absolutes[] = $part;
        }
    }

    return $first_slash . implode(DIRECTORY_SEPARATOR, $absolutes);
}

/**
 * 检查path是否为规范化的绝对路径名
 *
 * @param string $path
 * @param bool $strict path路径是否要真实存在
 * @return bool
 */
function is_realpath($path, $strict = false)
{
    $path = replace_path_separator($path);

    $real = realpath($path) == $path;
    if ($real || $strict) {
        return $real;
    }

    return get_absolute_path($path) == $path;
}

/**
 * 修改文件路径的后缀名
 *
 * @param string $filePath
 * @param string $suffix 后缀名，不含"."
 * @return string
 */
function change_suffix($filePath, $suffix)
{
    $oldSuffix = strrchr(basename($filePath), '.');

    if (false === $oldSuffix) {
        return "{$filePath}.{$suffix}";
    } else {
        return str_replace_last($oldSuffix, ".{$suffix}", $filePath);
    }
}

/**
 * 获取随机生成的文件名（10位随机数）
 *
 * @param mixed $param 文件扩展名，如果参数为`\Illuminate\Http\UploadedFile`对象，通过getExtension获取
 * @return string
 */
function random_filename($param = null)
{
    if ($param instanceof \Illuminate\Http\UploadedFile) {
        $extension = $param->extension();
    } else {
        $extension = (string) $param;
    }

    $name = str_random(10);
    return $extension ? "$name.$extension" : $name;
}

/**
 * 根据时间划分文件存放的相对路径
 *
 * @param string $type 名称单词
 * @return string
 */
function upload_path($type)
{
    return str_plural($type) . '/' . date('Ym') . '/' . date('d');
}

/**
 * 上传图片
 *
 * @param string $key
 * @param string $type 图片类型，不同类型存放于不同的目录，默认为 image
 * @param int $height 以 height 为最大高度，等比例缩小图片；为0时，不缩放
 * @return false|string
 */
function upload_image($key, $type = 'image', $height = 0)
{
    $request = request();

    $file = $request->file($key);
    $path = $file->storeAs(upload_path($type), random_filename($file));

    // 等比例缩小
    if ($height > 0) {
        $filePath = Storage::path($path);
        image_shrink($filePath, $height);
    }

    return $path;
}

/**
 * 以 height 为最大高度，等比例缩小图片
 *
 * @param string $filePath 图片路径
 * @param int $height 默认最大高度为 200
 */
function image_shrink($filePath, $height = 200)
{
    // 等比例缩小
    Image::make($filePath)->heighten($height, function ($constraint) {
        $constraint->upsize();
    })->save();
}

function is_image($file)
{
    $file = new File($file);
    return in_array($file->guessExtension(), ['jpeg', 'png', 'gif', 'bmp', 'svg']);
}

function image_url($path)
{
    if (empty($path) || 0 === strpos($path, 'http')) {
        return $path;
    }

    return Storage::url($path);
}

/**
 * 判断是否为链接
 *
 * @param string $value
 * @return bool
 */
function is_url($value)
{
    return boolval(filter_var($value, FILTER_VALIDATE_URL));
}

/**
 * 修改路径中的文件名
 *
 * @param string $path
 * @return string
 */
function change_filename($path)
{
    $parts = pathinfo($path);
    $filename = str_random(10);
    return $parts['dirname'] . "/{$filename}" . ($parts['extension'] ? ".{$parts['extension']}" : '');
}

/**
 * 两个数相除，如果除数为0，返回0
 *
 * @param float|int $dividend 被除数
 * @param float|int $divisor 除数
 * @return float|int
 */
function divide($dividend, $divisor)
{
    return 0 == $divisor ? 0 : ($dividend / $divisor);
}

/**
 * 合并一个或多个数组，但只合并在`array1`中存在的键名。
 * 如果`array1`是数字索引，以值作为键名，再合并。
 *
 * @param array $array1
 * @param array $array2
 * @return array
 */
function array_only_merge($array1, $array2)
{
    $num = func_num_args();
    $args = func_get_args();
    switch ($num) {
        case 0 :
            return [];
        case 1 :
            return $array1;
        case 2 :
            if (Arr::isAssoc($array1)) {
                $keys = array_keys($array1);
            } else {
                $keys = $array1;
                $array1 = array_fill_keys($keys, null);
            }
            return array_merge($array1, array_only($array2, $keys));
        default :
            $array1 = array_shift($args);
            $array2 = call_user_func_array('array_merge', $args);
            return array_only_merge($array1, $array2);
    }
}

/**
 * 删除数组中的某个值
 *
 * 如果 needle 在 haystack 中出现不止一次，则删除第一个匹配到的值，并返回对应的 key
 * 如果没匹配到，则返回 false
 *
 * @param array $haystack
 * @param mixed $needle
 * @return mixed
 */
function array_remove(&$haystack, $needle)
{
    $key = array_search($needle, $haystack);
    
    if (false !== $key) {
        unset($haystack[$key]);
        
        return $key;
    }
    
    return false;
}

/**
 * 获取对象相应的属性，类似 array_only
 *
 * @param stdClass $object
 * @param array $keys
 * @return array
 */
function object_only($object, $keys)
{
    $data = [];

    foreach ($keys as $key) {
        $data[$key] = $object->{$key};
    }

    return $data;
}

/**
 * 是否为安全的链接
 *
 * @param string $url
 * @param string $safeUrl
 * @return bool
 */
function is_safe_url($url, $safeUrl = '')
{
    if (empty($safeUrl)) {
        $safeUrl = config('app.url');
    }

    return 0 === strpos($url, $safeUrl);
}

/**
 * 返回数据验证不通过的响应信息
 *
 * @param string $message
 * @return \Illuminate\Http\JsonResponse
 */
function invalidation($message)
{
    return response()->json(['message' => $message], 422);
}

/**
 * 无访问权限时，返回的响应信息
 *
 * @param $message
 * @return \Illuminate\Http\JsonResponse
 */
function access_denied($message = '无访问权限')
{
    return response()->json(['message' => $message], 403);
}

/**
 * 获取单页查询个数，并限制最大值
 *
 * @param int $max
 * @return int
 */
function per_page($max = 50)
{
    $perPage = intval(request('per_page'));
    if ($perPage <= 0) {
        return 10;
    }

    return min($perPage, $max);
}

/**
 * 检查发起请求的客户端
 *
 * @param array|string|null $names 客户端名称：android, ios, mini_program, web
 * @return bool|string $name 为空时，返回客户端名称
 */
function app_client($names = null)
{
    static $clients = ['android', 'ios', 'mini_program', 'web'];

    $client = strtolower(request()->header('X-App-Client'));

    if (is_null($names)) {
        return in_array($client, $clients) ? $client : 'web';
    }

    return in_array($client, (array) $names);
}

/**
 * 获取客户端应用的产品版本号
 */
function client_product_version()
{
    return request()->header('X-Product-Version');
}

/**
 * 和客户端应用的版本号进行比较
 *
 * @param string $operator
 * @param string $version
 * @return mixed
 */
function app_version_compare($operator, $version)
{
    $appVersion = client_product_version();

    return version_compare($appVersion, $version, $operator);
}

/**
 * 记录日志
 *
 * @param $logPath
 * @param string $message
 */
function log_info($logPath, $message = '')
{
    $log = new Log();
    $log::useDailyFiles(storage_path() . '/logs/' . $logPath);
    $log::info($message);
    return $log;
}
